-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Introduce Converter
in junit-platform-commons
#4219
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There is plenty of work to do 🙃 The current highlights:
Any feedback would be highly appreciated! |
c31ca83
to
b19cba8
Compare
b19cba8
to
a7a8aa3
Compare
3304ad5
to
c886b7a
Compare
junit-jupiter-params/src/main/java/org/junit/jupiter/params/converter/ArgumentConverter.java
Outdated
Show resolved
Hide resolved
c886b7a
to
7ea91b8
Compare
Thanks for the draft! 👍 The tests are failing due to:
That's because
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks very promising! 👍
...m-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java
Outdated
Show resolved
Hide resolved
...m-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java
Show resolved
Hide resolved
...m-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java
Outdated
Show resolved
Hide resolved
...ns/src/main/java/org/junit/platform/commons/support/conversion/DefaultConversionService.java
Outdated
Show resolved
Hide resolved
|
||
import org.junit.platform.commons.support.conversion.TypedConversionService; | ||
|
||
// FIXME delete |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would make a good test case, though. We have existing tests that register services for tests using an extra class loader:
We could generalize and move that method to a test utility class (e.g. in junit-jupiter-api/src/testFixtures
) so it can be reused here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another possible integration test could be inspired by #3605.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could generalize and move that method to a test utility class (e.g. in
junit-jupiter-api/src/testFixtures
) so it can be reused here.
@marcphilipp fine if I do it in a separate PR? Mostly to keep the size of this one under control 🙃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Raised #4544.
When you add that, you'll also have to add it to |
2e17c2b
to
0c2faa7
Compare
I've been lagging behind with this one but I should be able to spend time on it in the upcoming weekend. |
0c2faa7
to
098c972
Compare
098c972
to
8ed6eb6
Compare
...m-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java
Show resolved
Hide resolved
...-jupiter-params/src/main/java/org/junit/jupiter/params/converter/TypedArgumentConverter.java
Outdated
Show resolved
Hide resolved
8ed6eb6
to
940d018
Compare
Would you like to include this in 5.13 too? I should have enough time in the upcoming days to finalize it. |
0a36152
to
e380b8f
Compare
...m-commons/src/main/java/org/junit/platform/commons/support/conversion/ConversionSupport.java
Outdated
Show resolved
Hide resolved
267ee7f
to
8b78923
Compare
...form-commons/src/main/java/org/junit/platform/commons/support/conversion/TypeDescriptor.java
Outdated
Show resolved
Hide resolved
...ons/src/main/java/org/junit/platform/commons/support/conversion/StringToObjectConverter.java
Outdated
Show resolved
Hide resolved
|
||
@Override | ||
protected @Nullable Locale convert(@Nullable String source) { | ||
return source != null ? Locale.forLanguageTag(source) : null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This class should return false
from canConvert
when source
is null
, shouldn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's possible that you commented before I refactored the Converter
hierarchy, so what I'm about to say might not align with what you had in mind 🙂
Currently, LocaleConverter
extends TypedConverter
, and I assume the latter should maintain support for null values, similar to TypedArgumentConverter
.
However, for the sake of this test, LocaleConverter
could also extend Converter
directly and have a more fine-grained canConvert
implementation, given that the underlying Locale.forLanguageTag
API is not supposed to accept null values.
Anyway, I think this test lost its value as DefaultConverter
uses Locale.forLanguageTag
natively (#4751), so I'll probably rewrite it differently or replace it with a more meaningful one.
...-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/Converter.java
Outdated
Show resolved
Hide resolved
@scordio Thanks! I've changed the setting. |
Now that Before exploring this in detail, I wanted to check your opinion first. |
8b78923
to
789d5d5
Compare
I think that could be useful and worth giving a try. 👍 |
789d5d5
to
4ea8824
Compare
4ea8824
to
17591cc
Compare
e146770
to
f2cdba7
Compare
f2cdba7
to
42cc962
Compare
// FIXME [NullAway] parameter type of referenced method is @NonNull, but parameter in functional interface method java.util.function.Function.apply(T) is @Nullable | ||
@SuppressWarnings("NullAway") | ||
public Optional<Class<?>> getWrapperType() { | ||
return Optional.ofNullable(type).map(ReflectionUtils::getWrapperType); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is a NullAway bug. I'll compose a small reproducer and raise an issue with the project.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, that is weird. How does NullAway
know about the nullability of the Function
type parameters of Optional.map
? Maybe it doesn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm still playing with it to understand it better. For example, the error is slightly different with a lambda:
public Optional<Class<?>> getWrapperType() {
return Optional.ofNullable(type).map(value -> ReflectionUtils.getWrapperType(value));
}
warning: [NullAway] passing @Nullable parameter 'value' where @NonNull is required
return Optional.ofNullable(type).map(value -> ReflectionUtils.getWrapperType(value));
^
(see http://t.uber.com/nullaway )
I would have expected NullAway to infer that value
is non-nullable, but maybe it has no way to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks to me like it thinks Optional.map
is typed as
<U> Optional<U> map(Function<? super @Nullable T, ? extends @Nullable U> mapper)
when it should be
<U> Optional<U> map(Function<? super @NonNull T, ? extends @Nullable U> mapper)
...mons/src/main/java/org/junit/platform/commons/support/conversion/StringToClassConverter.java
Outdated
Show resolved
Hide resolved
...-platform-commons/src/main/java/org/junit/platform/commons/support/conversion/Converter.java
Outdated
Show resolved
Hide resolved
@marcphilipp @sbrannen I think this is now ready for another round of reviews! A few points that still require work:
|
fe8883d
to
a57f5c9
Compare
...form-commons/src/main/java/org/junit/platform/commons/support/conversion/TypedConverter.java
Outdated
Show resolved
Hide resolved
|
||
@Override | ||
public final T convert(@Nullable S source, ConversionContext context) { | ||
return convert(source); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this extra indirection worth it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The advantage I see is that classes extending this one will have a simpler surface, without ConversionContext
appearing in the code.
Also, after the updates mentioned at #4219 (comment), this will prevent null
source.
* @see Converter | ||
*/ | ||
@API(status = EXPERIMENTAL, since = "6.0") | ||
public record ConversionContext(TypeDescriptor sourceType, TypeDescriptor targetType, ClassLoader classLoader) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the constructors need to be public so they can be used in unit tests for Converter
implementations, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept them public for any code invoking ConversionSupport.convert()
, which is not only DefaultArgumentConverter
but potentially user code as ConversionSupport
is a public API.
* @param context the context for the conversion; never {@code null} | ||
* @return {@code true} if the conversion is supported | ||
*/ | ||
boolean canConvert(ConversionContext context); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we pass source
here as well? In other words, could a Converter
only be able to convert S
only partially (for example, excluding null
)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I initially tried this direction but ended up with class cast exceptions due to Converter
having type parameters, so I eventually removed it.
I also checked how Spring does it in ConditionalConverter, and the strategy seemed to be the same, so I thought this was a common pitfall 🙂
Overview
ConversionService
SPI #853String
toNumber
conversion #3605I hereby agree to the terms of the JUnit Contributor License Agreement.
Definition of Done
@API
annotations